package com.tiancheng.trade.payment.channel.lkl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lkl.laop.sdk.exception.SDKException;
import com.lkl.laop.sdk.request.*;
import com.lkl.laop.sdk.request.model.V3LabsTradeLocationInfo;
import com.lkl.laop.sdk.request.model.V3LabsTradePreorderAlipayBus;
import com.lkl.laop.sdk.request.model.V3LabsTradePreorderWechatBus;
import com.lkl.laop.sdk.request.model.V3SacsSeparateRecvDatas;
import com.tiancheng.commom.pay.PayOrderAutoQueryConfig;
import com.tiancheng.commom.pay.lkl.LklPay;
import com.tiancheng.commom.pay.lkl.LklPayProperties;
import com.tiancheng.commom.pay.lkl.res.*;
import com.tiancheng.trade.commom.core.data.Result;
import com.tiancheng.trade.commom.core.enums.PaymentChannelEnum;
import com.tiancheng.trade.commom.core.enums.PaymentWayEnum;
import com.tiancheng.trade.commom.core.enums.SettleStatusEnum;
import com.tiancheng.trade.commom.core.exception.Asserts;
import com.tiancheng.trade.commom.core.exception.BusinessException;
import com.tiancheng.trade.commom.core.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.commom.core.utils.DateTimeUtil;
import com.tiancheng.trade.commom.core.utils.JsonUtil;
import com.tiancheng.trade.payment.bo.PaymentFlowDetailSettleDetailBO;
import com.tiancheng.trade.payment.bo.notify.LklPayNotifyBO;
import com.tiancheng.trade.payment.channel.AbstractPayChannel;
import com.tiancheng.trade.payment.channel.bo.*;
import com.tiancheng.trade.payment.channel.bo.paybo.AlipayResBO;
import com.tiancheng.trade.payment.channel.bo.paybo.WechatPayResBO;
import com.tiancheng.trade.payment.channel.enums.ChannelOrderStatusEnum;
import com.tiancheng.trade.payment.channel.ums.params.UmsUnifiedOrderParam;
import com.tiancheng.trade.payment.enums.ChannelRefundTypeEnum;
import com.tiancheng.trade.payment.enums.WithdrawalStatusEnum;
import com.tiancheng.trade.payment.mapper.PaymentFlowDetailMapper;
import com.tiancheng.trade.payment.mapper.PaymentOrderMapper;
import com.tiancheng.trade.payment.mapper.PaymentRefundFlowMapper;
import com.tiancheng.trade.payment.model.*;
import com.tiancheng.trade.payment.service.IPaymentFlowDetailSettleDetailService;
import com.tiancheng.trade.payment.service.IWithdrawalService;
import com.tiancheng.trade.payment.service.PaymentFlowDetailSettleService;
import com.tiancheng.trade.payment.util.CommonUtil;
import com.tiancheng.trade.payment.util.IPUtils;
import com.tiancheng.trade.payment.util.ObjectConvertUtil;
import com.tiancheng.trade.payment.util.helper.PaymentIdHelper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 拉卡拉支付通道
 */
@Slf4j
@Component
public class LklPayChannel implements AbstractPayChannel {

    @Resource
    private LklPayConfig lklPayConfig;
    @Resource
    private PaymentOrderMapper paymentOrderMapper;
    @Resource
    private PaymentFlowDetailMapper paymentFlowDetailMapper;
    @Resource
    private PaymentRefundFlowMapper paymentRefundFlowMapper;
    @Resource
    private IWithdrawalService withdrawalService;
    @Resource
    private PaymentFlowDetailSettleService paymentFlowDetailSettleService;
    @Resource
    private IPaymentFlowDetailSettleDetailService paymentFlowDetailSettleDetailService;

    @Override
    public PaymentChannelEnum getPaymentChannelEnum() {
        return PaymentChannelEnum.lkl_pay;
    }

    @Override
    public Result<UnifiedOrderResBO> unifiedOrder(UnifiedOrderBO unifiedOrderBO) throws BusinessException {
        Assert.isTrue(null != unifiedOrderBO.getAmount(), "订单支付总金额有误");
        // 子订单商品信息-商品维度清分
        List<UnifiedOrderResBO.SubOrder> subOrders = new ArrayList<>();
        unifiedOrderBO.getSubOrders().forEach(subOrderBO -> {
            UmsUnifiedOrderParam.UmsProduct umsProduct = new UmsUnifiedOrderParam.UmsProduct();
            umsProduct.setGoodsId(subOrderBO.getProductCode());
            // TODO 微信、支付宝支付需要限制商品id不超过32位
            umsProduct.setGoodsId(CommonUtil.subString(subOrderBO.getProductCode(), 32));
            umsProduct.setGoodsName(CommonUtil.orderNameHandle(subOrderBO.getProductName()));
            umsProduct.setQuantity(subOrderBO.getProductCount());
            umsProduct.setPrice(subOrderBO.getAmount()); // 传实付金额
            umsProduct.setSubMerchantId(subOrderBO.getSubMerchantId());
            umsProduct.setMerOrderId(subOrderBO.getSubFlowId());
            umsProduct.setSubOrderAmount(subOrderBO.getAmount());
            UnifiedOrderResBO.SubOrder subOrder = ObjectConvertUtil.convert(umsProduct, UnifiedOrderResBO.SubOrder.class).get();
            subOrder.setEnterpriseCode(subOrderBO.getEnterpriseCode());
            subOrder.setSubOrderId(subOrderBO.getSubOrderId());
            subOrders.add(subOrder);
        });
        Assert.isTrue(null != unifiedOrderBO.getAmount(), "订单支付总金额有误");
        UnifiedOrderResBO unifiedOrderResBO = new UnifiedOrderResBO();
        unifiedOrderResBO.setSubOrders(subOrders);
        PaymentWayEnum paymentWayEnum = PaymentWayEnum.getByCode(unifiedOrderBO.getPayWay()).get();
        Result<UnifiedOrderResBO> result = new Result<>();
        try {
            LklPayProperties config = initLklPayConfig(unifiedOrderBO.getOrgPaymentChannelId());
            V3LabsTransPreorderEncryRequest params = new V3LabsTransPreorderEncryRequest();
            params.setMerchantNo(config.getMerchantNo());
            params.setTermNo(config.getTermNo());
            params.setOutTradeNo(unifiedOrderBO.getFlowId());
            /**
             * 41:NATIVE（（ALIPAY，云闪付支持，京东白条分期）
             * 51:JSAPI（微信公众号支付，支付宝服务窗支付，银联JS支付，翼支付JS支付, 拉卡拉钱包支付, 支付宝小程序支付）
             */
            params.setTransType("51");
            params.setTotalAmount(unifiedOrderBO.getOrderAmount().toString());
            params.setNotifyUrl(config.getNotifyUrl());
            params.setRemark(unifiedOrderBO.getOrderName());

            //地址位置信息
            V3LabsTradeLocationInfo v3LabsTradePreorderLocationInfo1 = new V3LabsTradeLocationInfo(IPUtils.getIp());
            params.setLocationInfo(v3LabsTradePreorderLocationInfo1);

            switch (paymentWayEnum) {
                case WECHAT -> {
                    // 微信支付
                    Asserts.isNotEmpty(unifiedOrderBO.getSubAppId(), "高诚支付中台：微信支付必传微信appId！");
                    Asserts.isNotEmpty(unifiedOrderBO.getOpenid(), "高诚支付中台：微信支付必传微信openId！");
                    Asserts.isNotEmpty(unifiedOrderBO.getSubAppId(), "高诚支付中台：微信支付必传微信appId！");
                    params.setAccountType("WECHAT");

                    V3LabsTradePreorderWechatBus wechatBus = new V3LabsTradePreorderWechatBus();
                    wechatBus.setSubAppid(unifiedOrderBO.getSubAppId());
                    wechatBus.setUserId(unifiedOrderBO.getOpenid());
                    wechatBus.setGoodsTag(unifiedOrderBO.getGoodsTag());
                    if (null == unifiedOrderBO.getPayExpiryTime()) {
                        // 没有设置过期时间的情况，默认21分钟后过期（订单中心给的默认值）
                        unifiedOrderBO.setPayExpiryTime(LocalDateTime.now().plusMinutes(30));
                    }
                    wechatBus.setTimeoutExpress(String.valueOf(Math.abs(Duration.between(LocalDateTime.now(), unifiedOrderBO.getPayExpiryTime()).toMinutes())));
                    params.setAccBusiFields(wechatBus);
                    LklBaseRes<LklPreorderRes> wxPayResult = initLklPay(unifiedOrderBO.getOrgPaymentChannelId()).wechatPay(params);
                    Asserts.isTrue(wxPayResult.isOK(), getPaymentChannelEnum().getDesc() + "支付失败！");
                    unifiedOrderResBO.setOutTradeNo(wxPayResult.getRespData().getTradeNo());
                    unifiedOrderResBO.setTransactionId(wxPayResult.getRespData().getTradeNo());
                    unifiedOrderResBO.setPayInfo(JsonUtil.toJsonString(JsonUtil.fromJson(JsonUtil.toJsonString(wxPayResult.getRespData().getAccRespFields()), WechatPayResBO.class)));
                }
                // 处理相响应结果
                case ALIPAY -> {
                    // 支付宝支付
                    params.setTransType("41");
                    params.setAccountType("ALIPAY");

                    //支付宝主扫场景下acc_busi_fields域内容
                    V3LabsTradePreorderAlipayBus alipayBus = new V3LabsTradePreorderAlipayBus();
                    alipayBus.setUserId(unifiedOrderBO.getOpenid());
                    alipayBus.setDisablePayChannels("credit_group");
                    if (null == unifiedOrderBO.getPayExpiryTime()) {
                        // 没有设置过期时间的情况，默认21分钟后过期（订单中心给的默认值）
                        unifiedOrderBO.setPayExpiryTime(LocalDateTime.now().plusMinutes(30));
                    }
                    alipayBus.setTimeoutExpress(String.valueOf(Math.abs(Duration.between(LocalDateTime.now(), unifiedOrderBO.getPayExpiryTime()).toMinutes())));
                    alipayBus.setMinAge("18");
                    params.setAccBusiFields(alipayBus);
                    LklBaseRes<LklPreorderRes> aliPayResult = initLklPay(unifiedOrderBO.getOrgPaymentChannelId()).aliPay(params);
                    Asserts.isTrue(aliPayResult.isOK(), getPaymentChannelEnum().getDesc() + "支付失败！");
                    // 拉卡拉订单号
                    unifiedOrderResBO.setOutTradeNo(aliPayResult.getRespData().getTradeNo());
                    // 结算订单号
                    unifiedOrderResBO.setTransactionId(aliPayResult.getRespData().getLogNo());
                    if (StringUtils.isNotEmpty(aliPayResult.getRespData().getAccRespFields().getCode())) {
                        unifiedOrderResBO.setPayInfo(JsonUtil.toJsonString(new AlipayResBO(null, aliPayResult.getRespData().getAccRespFields().getCode())));
                    } else {
                        // TODO 其他情况
                    }
                }
                case CORPPAY -> {
                    // 对公支付

                }
            }
            result.setData(unifiedOrderResBO);
            result.setRet(0);
            result.setMsg("高诚统一支付下单成功");
            return result;
        } catch (BusinessException e) {
            log.error(e.getMessage());
            result.setRet(1);
            result.setMsg("高诚统一支付下单失败:" + e.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage());
            result.setRet(1);
            result.setMsg("高诚统一支付下单失败!");
        }
        return null;
    }

    /**
     * 查询拉卡拉订单信息
     *
     * @param getUnifiedOrderBO
     * @return
     * @throws BusinessException
     */
    @Override
    public Result<GetUnifiedOrderResBO> get(GetUnifiedOrderBO getUnifiedOrderBO) throws BusinessException {
        QueryWrapper<PaymentOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flow_id", getUnifiedOrderBO.getOrderId());
        queryWrapper.eq("user_id", getUnifiedOrderBO.getUid());
        PaymentOrder paymentOrder = paymentOrderMapper.selectOne(queryWrapper);
        Assert.isTrue(null != paymentOrder, "未查询到相应流水");
        V3LabsQueryTradequeryRequest params = new V3LabsQueryTradequeryRequest();
        params.setOutTradeNo(paymentOrder.getFlowId());
        params.setTradeNo(paymentOrder.getTradeNo());
        Result<GetUnifiedOrderResBO> result = new Result<>();
        try {
            LklBaseRes<LklOrderQueryRes> getResult = initLklPay(getUnifiedOrderBO.getOrgPaymentChannelId()).queryOrderPay(params);
            // 处理相响应结果
            // 处理响应结果
            result.setRet(getResult.isOK() ? 0 : 1);
            result.setMsg(StringUtils.isNotEmpty(getResult.getMsg()) ? getResult.getMsg() : "");
            GetUnifiedOrderResBO getUnifiedOrderResBO = new GetUnifiedOrderResBO();
            getUnifiedOrderResBO.setOrderId(getResult.getRespData().getOutTradeNo());
            getUnifiedOrderResBO.setTransactionId(getResult.getRespData().getTradeNo());
            getUnifiedOrderResBO.setTradeNo(getResult.getRespData().getTradeNo());
            String state = getResult.getRespData().getTradeState();
            switch (state) {
                case "INIT", "CREATE" -> getUnifiedOrderResBO.setOrderStatus(ChannelOrderStatusEnum.ing);
                case "SUCCESS" -> getUnifiedOrderResBO.setOrderStatus(ChannelOrderStatusEnum.success);
                case "FAIL", "UNKNOWN", "CLOSE" -> getUnifiedOrderResBO.setOrderStatus(ChannelOrderStatusEnum.fail);
                default -> log.warn("不支持的订单状态:{}", state);
            }

            if (StringUtils.isNotEmpty(getResult.getRespData().getTradeTime())) {
                getUnifiedOrderResBO.setPayTime(DateTimeUtil.string2LocalDateTime(getResult.getRespData().getTradeTime(), DateTimeUtil.fmt_yyyyMMddHHmmss));
            }
            if (StringUtils.isNotEmpty(getResult.getRespData().getPayerAmount())) {
                getUnifiedOrderResBO.setAmount(Integer.parseInt(getResult.getRespData().getPayerAmount()));
            } else if (StringUtils.isNotEmpty(getResult.getRespData().getTotalAmount())) {
                getUnifiedOrderResBO.setAmount(Integer.parseInt(getResult.getRespData().getTotalAmount()));
            }
            result.setData(getUnifiedOrderResBO);
        } catch (Exception e) {
            log.error(e.getMessage());
            result.setRet(1);
            result.setMsg("查询订单失败");
        }
        return result;
    }

    @Override
    public Result<RefundOrderResBO> refund(RefundOrderBO refundOrderBO) throws BusinessException {
        QueryWrapper<PaymentOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flow_id", refundOrderBO.getOrderId());
        queryWrapper.eq("user_id", refundOrderBO.getUid());
        PaymentOrder paymentOrder = paymentOrderMapper.selectOne(queryWrapper);

        Assert.isTrue(null != paymentOrder, "未查询到相应流水");
        Assert.isTrue(!StringUtils.isEmpty(paymentOrder.getPaymentWay()), "流水支付方式异常");

        // 1、判断原支付订单是分账，是分账->判断是否已经发起分账->没有发起则发起分账
        List<PaymentFlowDetailSettle> paymentFlowDetailSettles = paymentFlowDetailSettleService.list(new LambdaQueryWrapper<PaymentFlowDetailSettle>()
                .in(PaymentFlowDetailSettle::getSubFlowId, refundOrderBO.getSettles().stream().map(RefundOrderSettleBO::getSubPayFlowId).collect(Collectors.toSet())));
        Asserts.isNotEmpty(paymentFlowDetailSettles, "支付分账信息为空！");
        // 需要分账的流水
        List<PaymentFlowDetailSettle> needSettles = new ArrayList<>();
        // 需要退分账的流水
        List<PaymentFlowDetailSettle> ingSettles = new ArrayList<>();
        for (PaymentFlowDetailSettle paymentFlowDetailSettle : paymentFlowDetailSettles) {
            if (paymentFlowDetailSettle.getSettleStatus().equals(SettleStatusEnum.WAIT.getCode())
                    || paymentFlowDetailSettle.getSettleStatus().equals(SettleStatusEnum.FAIL.getCode())) {
                // 结算状态为待结算、结算失败，发起分账
                needSettles.add(paymentFlowDetailSettle);
            } else if (paymentFlowDetailSettle.getSettleStatus().equals(SettleStatusEnum.ING.getCode())
                    || paymentFlowDetailSettle.getSettleStatus().equals(SettleStatusEnum.SUCCESS.getCode())) {
                ingSettles.add(paymentFlowDetailSettle);
            }
        }
        // 结算成功的流水项
        List<PaymentFlowDetailSettle> successed = new ArrayList<>();
        // 结算成功的流水分账明细项
        List<PaymentFlowDetailSettleDetail> successDetails = new ArrayList<>();
        // 提现记录集合
        List<Withdrawal> withdrawals = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(needSettles)) {
            List<PaymentFlowDetailSettleDetail> pfdsds = paymentFlowDetailSettleDetailService.list(new LambdaQueryWrapper<PaymentFlowDetailSettleDetail>()
                    .in(PaymentFlowDetailSettleDetail::getSubFlowId, needSettles.stream().map(PaymentFlowDetailSettle::getSubFlowId).collect(Collectors.toSet())));
            for (PaymentFlowDetailSettle needSettle : needSettles) {

                String withdrawalFlowId = PaymentIdHelper.getWithdrawalFlowId(needSettle.getSubFlowId());

                LklPayProperties lklPayProperties = initLklPayConfig(needSettle.getOrgPaymentChannelId());
                V3SacsSeparateRequest settleItem = new V3SacsSeparateRequest();
                settleItem.setMerchantNo(lklPayProperties.getMerchantNo());
                settleItem.setLogNo(paymentOrder.getTransactionId());
                settleItem.setLogDate(DateTimeUtil.format(LocalDateTime.now(), DateTimeUtil.yyyyMMdd));
                settleItem.setOutSeparateNo(PaymentIdHelper.getWithdrawalFlowId(needSettle.getFlowId()));
                settleItem.setNotifyUrl(lklPayProperties.getNotifyUrl());
                //分账接收数据对象

                List<V3SacsSeparateRecvDatas> recvDatas = new ArrayList<>();
                List<PaymentFlowDetailSettleDetail> details = pfdsds.stream().filter(p -> p.getSubFlowId().equals(needSettle.getSubFlowId())).collect(Collectors.toList());
                details.forEach(detail -> {
                    V3SacsSeparateRecvDatas recvData = new V3SacsSeparateRecvDatas();
                    if (detail.getSubMerchantType().equals(1)) {
                        recvData.setRecvMerchantNo(detail.getSettleMerchantId());
                    } else {
                        recvData.setRecvNo(detail.getSettleMerchantId());
                    }
                    recvData.setSeparateValue(detail.getAmount().toString());
                    detail.setWithdrawalId(withdrawalFlowId);
                    recvDatas.add(recvData);
                });

                settleItem.setTotalAmt(String.valueOf(details.stream().mapToInt(PaymentFlowDetailSettleDetail::getAmount).sum()));
                settleItem.setLklOrgNo("1");
                settleItem.setCalType("0");
                settleItem.setRecvDatas(recvDatas);
                // 拉卡拉分账返回
                try {
                    LklBaseRes<LklSeparateRes> lklSeparateResLklBaseRes = new LklPay(lklPayProperties).orderSettle(settleItem);
                    if (lklSeparateResLklBaseRes.isOK()) {
                        // 拉卡拉分账单号
                        String separateNo = lklSeparateResLklBaseRes.getRespData().getSeparateNo();
                        needSettle.setChannelSettleNo(separateNo);
                        // 保存提现记录
                        Withdrawal withdrawal = new Withdrawal();
                        withdrawal.setWithdrawalId(withdrawalFlowId);
                        withdrawal.setSsn(separateNo);
                        PaymentFlowDetailSettleDetail tradeMerchant = tradeMerchant(details);
                        withdrawal.setMerchantRegId(tradeMerchant.getMerchantRegId());
                        withdrawal.setMerchantCode(tradeMerchant.getMerchantCode());
                        withdrawal.setMerchantName(tradeMerchant.getMerchantName());
                        withdrawal.setSubMerchantId(tradeMerchant.getSubMerchantId());
                        withdrawal.setEnterpriseCode(tradeMerchant.getSettleMerchantId());
                        withdrawal.setAmount(Integer.parseInt(settleItem.getTotalAmt()));
                        withdrawal.setFee(0);
                        withdrawal.setWithdrawalStatus(WithdrawalStatusEnum.ING.getCode());
                        withdrawal.setOrgPaymentChannelId(needSettle.getOrgPaymentChannelId());
                        withdrawal.setPaymentChannel(needSettle.getPaymentChannel());
                        withdrawal.setCompleteTime(LocalDateTime.now());
                        withdrawal.setUpdateTime(LocalDateTime.now());
                        withdrawal.setCreateTime(LocalDateTime.now());

                        needSettle.setSettleStatus(SettleStatusEnum.ING.getCode());
                        successDetails.addAll(details);
                        withdrawals.add(withdrawal);
                        successed.add(needSettle);
                    }
                } catch (SDKException e) {
                    throw new RuntimeException(e);
                }
            }

            // 修改状态、保存提现记录
            // TODO 更新
            List<PaymentFlowDetailSettleDetail> updatePfdsds = new ArrayList<>();
            Set<PaymentFlowDetailSettle> updatePfds = successed.stream().map(d -> {
                PaymentFlowDetailSettle pfds = new PaymentFlowDetailSettle();
                pfds.setId(d.getId());
                pfds.setSettleStatus(d.getSettleStatus());
                pfds.setChannelSettleNo(d.getChannelSettleNo());
                return pfds;
            }).collect(Collectors.toSet());
            for (PaymentFlowDetailSettleDetail detail : successDetails) {
                PaymentFlowDetailSettleDetail item = new PaymentFlowDetailSettleDetail();
                item.setId(detail.getId());
                item.setSettleStatus(SettleStatusEnum.ING.getCode());
                item.setWithdrawalId(detail.getWithdrawalId());
                updatePfdsds.add(item);
            }

            withdrawalService.saveBatch(withdrawals);
            paymentFlowDetailSettleService.updateBatchById(updatePfds);
            paymentFlowDetailSettleDetailService.updateBatchById(updatePfdsds);
        }
        // 2、分账退回
        List<PaymentFlowDetailSettle> backFlows = new ArrayList<>();
        backFlows.addAll(needSettles);
        backFlows.addAll(ingSettles);
        if (CollectionUtils.isNotEmpty(backFlows)) {
            for (PaymentFlowDetailSettle backFlow : backFlows) {
                // TODO 等待完善后续流程
                //new LklPay(backFlow.getOrgPaymentChannelId()).orderSettleFallback();
            }
        }
        // 3、退款


        V3LabsRelationRefundRequest params = new V3LabsRelationRefundRequest();

        params.setOutTradeNo(refundOrderBO.getRefundId());
        params.setRefundAmount(refundOrderBO.getAmount().toString());
        params.setRefundReason(refundOrderBO.getReason());
        params.setOriginOutTradeNo(paymentOrder.getFlowId());
        params.setOriginTradeNo(paymentOrder.getTradeNo());


        Result<RefundOrderResBO> result = new Result<>();
        RefundOrderResBO refundOrderResBO = new RefundOrderResBO();
        try {
            LklBaseRes<LklRefundRes> refundResult = initLklPay(refundOrderBO.getOrgPaymentChannelId()).refund(params);
            Asserts.isTrue(refundResult.isOK(), StringUtils.isNotEmpty(refundResult.getMsg()) ? refundResult.getMsg() : "退款失败！");
            LklRefundRes respData = refundResult.getRespData();
            // 拉卡拉退款订单号
            String tradeNo = respData.getTradeNo();
            // 实际退款金额
            String payerAmount = respData.getPayerAmount();
            if (StringUtils.isNotEmpty(payerAmount)) {
                refundOrderResBO.setRefundInvoiceAmount(Integer.parseInt(payerAmount));
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            result.setRet(1);
            result.setMsg("退款失败！");
        }

        // 延迟退款处理，实退金额返回0
        refundOrderResBO.setRefundTypeEnum(ChannelRefundTypeEnum.ALL);
        result.setData(refundOrderResBO);
        return result;
    }

    private PaymentFlowDetailSettleDetail tradeMerchant(List<PaymentFlowDetailSettleDetail> details) {
        return details.stream().filter(d -> d.getSubMerchantType().equals(1)).findFirst().get();
    }

    @Override
    public Result<GetRefundOrderResBO> getRefund(GetRefundOrderBO getRefundOrderBO) throws BusinessException {

        QueryWrapper<PaymentRefundFlow> conditions = new QueryWrapper<>();
        conditions.eq("user_id", getRefundOrderBO.getUid());
        conditions.eq("flow_id", getRefundOrderBO.getRefundId());
        PaymentRefundFlow refundFlow = paymentRefundFlowMapper.selectOne(conditions);
        Assert.isTrue(null != refundFlow, "未查询到相应退款流水");

        QueryWrapper<PaymentOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flow_id", refundFlow.getPayFlowId());
        queryWrapper.eq("user_id", getRefundOrderBO.getUid());
        PaymentOrder paymentOrder = paymentOrderMapper.selectOne(queryWrapper);
        Assert.isTrue(null != paymentOrder, "未查询到相应支付流水");
        Assert.isTrue(!StringUtils.isEmpty(paymentOrder.getPaymentWay()), "流水支付方式异常");

        V3LamsTradeTradeRefundQueryRequest params = new V3LamsTradeTradeRefundQueryRequest();

        params.setOutTradeNo(refundFlow.getFlowId());
        params.setOriginTradeDate(DateTimeUtil.formatter(refundFlow.getCreateTime(), DateTimeUtil.yyyyMMdd));
        params.setOriginOutTradeNo(paymentOrder.getFlowId());
        params.setOriginBizType("4");

        Result<GetRefundOrderResBO> result = new Result<>();
        try {
            LklBaseRes<LklOrderQueryRes> refundResult = initLklPay(getRefundOrderBO.getOrgPaymentChannelId()).getRefund(params);
            log.info("银联shop退款查询返回:{}", JsonUtil.toJsonString(refundResult));

            result.setRet(refundResult.isOK() ? 0 : 1);
            result.setMsg(refundResult.getMsg());
            GetRefundOrderResBO resBO = new GetRefundOrderResBO();
            resBO.setRefundId(refundFlow.getFlowId());
            /*resBO.setTransactionId(refundFlow.get());
            resBO.setTradeNo(refundOrderResult.getTargetOrderId());*/
            // 退款时间，银联未返回，使用退款流水表中退款时间
            resBO.setRefundTime(refundFlow.getFlowTime());

            // 退款状态
            resBO.setChannelOrderStatusEnum(ChannelOrderStatusEnum.ing);
            String channelRefundStatus = refundResult.getRespData().getTradeState();

            if (channelRefundStatus.equals("SUCCESS")) {
                // C扫B查询返回
                resBO.setChannelOrderStatusEnum(ChannelOrderStatusEnum.success);
            } else if (channelRefundStatus.equals("FAIL")) {
                resBO.setChannelOrderStatusEnum(ChannelOrderStatusEnum.fail);
            }
            result.setData(resBO);
        } catch (Exception e) {
            log.error(e.getMessage());
            result.setRet(1);
            result.setMsg("查询退款失败");
        }
        return result;
    }

    @Override
    public Result close(CloseOrderBO closeOrderBO) throws BusinessException {
        QueryWrapper<PaymentOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("flow_id", closeOrderBO.getOrderId());
        queryWrapper.eq("user_id", closeOrderBO.getUid());
        PaymentOrder paymentOrder = paymentOrderMapper.selectOne(queryWrapper);
        Assert.isTrue(null != paymentOrder, "未查询到相应支付流水");
        Assert.isTrue(!StringUtils.isEmpty(paymentOrder.getPaymentWay()), "流水支付方式异常");

        V3LabsRelationCloseRequest params = new V3LabsRelationCloseRequest();
        params.setOriginOutTradeNo(paymentOrder.getFlowId());
        params.setOriginTradeNo(paymentOrder.getTradeNo());
        Result<?> result = new Result<>();
        try {
            LklBaseRes<String> refundResult = initLklPay(closeOrderBO.getOrgPaymentChannelId()).close(params);
            Asserts.isTrue(refundResult.isOK(), StringUtils.isNotEmpty(refundResult.getMsg()) ? refundResult.getMsg() : "退款失败！");
            log.info("【拉卡拉】订单关闭返回:{}", JsonUtil.toJsonString(refundResult));

            result.setRet(refundResult.isOK() ? 0 : 1);
            result.setMsg(refundResult.getMsg());
        } catch (Exception e) {
            log.error(e.getMessage());
            result.setRet(1);
            result.setMsg("【拉卡拉】关闭订单失败");
        }
        result.setMsg("【拉卡拉】关闭订单成功");
        return result;
    }

    @Override
    public PayResultBO payResult(Map<String, Object> payResult) {
        //  消息验证sign
        LklPayNotifyBO lklPayNotifyBO = JsonUtil.fromJson(JsonUtil.toJsonString(payResult), LklPayNotifyBO.class);
        Asserts.isTrue(null != lklPayNotifyBO, "拉卡拉回调内容为空！");

        PayResultBO payResultBO = new PayResultBO();
        //TODO 待确认订单状态，是否需要再次发起查询
        BusinessErrorInfoEnum.CHANNEL_CALLBACK_PAY_UNKNOWN_STATUS.assertIsTrue((StringUtils.isNotEmpty(lklPayNotifyBO.getTradeStatus()) && lklPayNotifyBO.getTradeStatus().equals("SUCCESS")));

        Integer totalAmount = Integer.parseInt(lklPayNotifyBO.getTotalAmount());
        payResultBO.setStatus("success");
        payResultBO.setOrderId(lklPayNotifyBO.getOutTradeNo());
        payResultBO.setTradeNo(lklPayNotifyBO.getTradeNo());
        payResultBO.setAmount(Integer.parseInt(lklPayNotifyBO.getPayerAmount()));
        payResultBO.setCouponAmount(totalAmount - payResultBO.getAmount());
        if (StringUtils.isNotEmpty(lklPayNotifyBO.getTradeTime())) {
            payResultBO.setPayTime(DateTimeUtil.string2LocalDateTime(lklPayNotifyBO.getTradeTime(), DateTimeUtil.fmt_yyyyMMddHHmmss));
        }

        return payResultBO;
    }

    @Override
    public RefundResultBO refundResult(Map<String, Object> refundResult) {
        return null;
    }

    @Override
    public Result settleV2(List<PaymentFlowDetailSettle> detailSettles, List<PaymentFlowDetailSettleDetail> detailSettlesDetails) throws BusinessException {
        return null;
    }

    @Override
    public boolean autoQueryStatus(Long orgPaymentChannelId) {
        LklPayProperties lklPayProperties = lklPayConfig.getByOrgPayChannelId(orgPaymentChannelId);
        return lklPayProperties.autoQueryStatus();
    }

    @Override
    public PayOrderAutoQueryConfig getOrderAutoQueryConfig(Long orgPaymentChannelId) {
        return null;
    }

    private LklPay initLklPay(long orgPaymentChannelId) throws SDKException {
        return new LklPay(initLklPayConfig(orgPaymentChannelId));
    }

    private LklPayProperties initLklPayConfig(Long orgPaymentChannelId) {
        return lklPayConfig.getByOrgPayChannelId(orgPaymentChannelId);
    }
}
